package com.xf.service.impl;

import cc.mrbird.febs.common.datasource.starter.organization.OrganizationBroker;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xf.common.core.constant.CommonConstants;
import com.xf.common.core.domain.Constants;
import com.xf.common.core.domain.DmpResult;
import com.xf.common.core.entity.CurrentUser;
import com.xf.common.core.entity.dmp.DmpAuthRole;
import com.xf.common.core.entity.dmp.DmpAuthUser;
import com.xf.common.core.entity.dmp.DmpAuthUserRoleRelation;
import com.xf.common.core.entity.dmp.RegisterUserDto;
import com.xf.common.core.entity.system.DmpUserAssignDto;
import com.xf.common.core.entity.system.SystemUser;
import com.xf.common.core.enums.UserCacheKeyEnum;
import com.xf.common.core.enums.YesOrNoEnum;
import com.xf.common.core.exception.FebsException;
import com.xf.common.core.utils.BeanUtils;
import com.xf.common.core.utils.FebsUtil;
import com.xf.common.core.utils.WebUtil;
import com.xf.common.redis.cache.DmpRedisCache;
import com.xf.mapper.DmpAuthUserMapper;
import com.xf.service.DmpAuthRoleService;
import com.xf.service.DmpAuthUserRoleRelationService;
import com.xf.service.DmpAuthUserService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author JoeyLiu
 * @create 2022-04-01 13:59
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class DmpAuthUserServiceImpl extends ServiceImpl<DmpAuthUserMapper, DmpAuthUser> implements DmpAuthUserService {


    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private DmpRedisCache redisCache;
    @Resource
    private DmpAuthUserRoleRelationService userRoleRelationService;
    @Resource
    private DmpAuthRoleService dmpAuthRoleService;


    @Override
    public IPage<DmpAuthUser> page(IPage page, String aliasOrName, Integer state) {
        return baseMapper.pageWithCreatedUser(page, aliasOrName, state);
    }


    @Override
    public DmpResult assign(DmpUserAssignDto dmpUserAssignDto) {
        try {
            userRoleRelationService.deleteByUserId(dmpUserAssignDto.getUserId());
            redisCache.del(UserCacheKeyEnum.RESOURCE.getKey(dmpUserAssignDto.getUserId().toString()));
            userRoleRelationService.saveBatch(dmpUserAssignDto.getRoleRelationList());
            return DmpResult.success("分配成功");
        } catch (Exception e) {
            log.error(e.getMessage());
            return DmpResult.failed("分配失败");

        }
    }

    @Override
    public DmpAuthUser findUserDetail(String username) {
        DmpAuthUser param = new DmpAuthUser();
        param.setUserName(username);
        List<DmpAuthUser> users = this.baseMapper.findUserDetail(param);
        return CollectionUtils.isNotEmpty(users) ? users.get(0) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLoginTime(String username) {
        DmpAuthUser user = new DmpAuthUser();
//        user.setLastSigninTime(new Date());
        this.baseMapper.update(user, new LambdaQueryWrapper<DmpAuthUser>().eq(DmpAuthUser::getUserName, username));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)

    public void createUser(DmpAuthUser user) {
        // 创建用户
        user.setAvatar(SystemUser.DEFAULT_AVATAR);
        user.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
        SystemUser systemUser = new SystemUser();
        BeanUtils.copyPropertiesIgnoreNullValue(user, systemUser);
        systemUser.setUserName(user.getUserName());
        systemUser.setIsGlobalAdmin(false);
        systemUser.setIsAdmin(false);
        systemUser.setIsAdmin(false);
        String organizationId = systemUser.getOrganizationId();
        systemUser.setOrganizationId(null);
        systemUser.setState(SystemUser.STATE_VALID);
        systemUser.setUserCode(IdWorker.getIdStr());
        systemUser.setRemark("手动添加用户");
        //租户初始化
        OrganizationBroker.runAs(organizationId, (tenantId -> baseMapper.insert(systemUser)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(DmpAuthUser user) {
        // 更新用户
        user.setPassword(null);
        user.setUserName(null);
        user.setCreatedDate(null);
        user.setUpdatedDate(new Date());
        updateById(user);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUsers(String[] userIds) {
        List<String> list = Arrays.asList(userIds);
        removeByIds(list);
        // 删除用户角色
//        this.userRoleService.deleteUserRolesByUserId(userIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(DmpAuthUser user) throws FebsException {
        user.setPassword(null);
        user.setUserName(null);
        user.setStatus(null);
        if (isCurrentUser(user.getId())) {
            updateById(user);
        } else {
            throw new FebsException("您无权修改别人的账号信息！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAvatar(String avatar) {
        DmpAuthUser user = new DmpAuthUser();
        user.setAvatar(avatar);
        String currentUsername = FebsUtil.getCurrentUsername();
        this.baseMapper.update(user, new LambdaQueryWrapper<DmpAuthUser>().eq(DmpAuthUser::getUserName, currentUsername));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(String password) {
        DmpAuthUser user = new DmpAuthUser();
        user.setPassword(password);
        String currentUsername = FebsUtil.getCurrentUsername();
        this.baseMapper.update(user, new LambdaQueryWrapper<DmpAuthUser>().eq(DmpAuthUser::getUserName, currentUsername));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(String[] usernames) {
        DmpAuthUser params = new DmpAuthUser();
        params.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
        List<String> list = Arrays.asList(usernames);
        this.baseMapper.update(params, new LambdaQueryWrapper<DmpAuthUser>().in(DmpAuthUser::getUserName, list));

    }

    private boolean isCurrentUser(Long id) {
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        return currentUser != null && id.equals(currentUser.getUserId());
    }

    @Override
    public DmpResult<DmpAuthUser> selectByUserCode(String userCode) {
        DmpAuthUser dmpAuthUser = redisCache.getEx(UserCacheKeyEnum.USER.getKey(userCode),
                Duration.ofSeconds(30),
                () -> this.baseMapper.selectByUserCode(userCode));
        return DmpResult.data(dmpAuthUser);
    }

    @Override
    public DmpResult<DmpAuthUser> selectByNameOrEmail(String user) {
        DmpAuthUser dmpAuthUser = redisCache.getEx(UserCacheKeyEnum.USER.getKey(user),
                Duration.ofSeconds(30),
                () -> this.baseMapper.selectByNameOrEmail(user));
        return DmpResult.data(dmpAuthUser);
    }

    @Override
    public SystemUser findByName(String username) {
        return redisCache.getEx(UserCacheKeyEnum.USER.getKey(username), Duration.ofSeconds(Constants.USER_TIME_OUT), () -> {
            DmpAuthUser dmpAuthUser = this.baseMapper.findByName(username);
            Assert.notNull(dmpAuthUser, "用户未注册");
            return createUserDto(dmpAuthUser);
        });
    }

    private SystemUser createUserDto(DmpAuthUser user) {
        SystemUser systemUser = new SystemUser();
        BeanUtils.copyPropertiesIgnoreNullValue(user, systemUser);
        List<String> roleList = new ArrayList<>();
        systemUser.setRoleList(roleList);
        //用户和角色关系表
        List<DmpAuthUserRoleRelation> userRoleRelationList = userRoleRelationService
                .list(Wrappers.lambdaQuery(DmpAuthUserRoleRelation.class)
                        .select(DmpAuthUserRoleRelation::getRoleId)
                        .eq(DmpAuthUserRoleRelation::getUserId, systemUser.getId()));
        if (CollectionUtils.isNotEmpty(userRoleRelationList)) {
            List<DmpAuthRole> userRoleList = dmpAuthRoleService.listByIds(userRoleRelationList.
                    stream().map(DmpAuthUserRoleRelation::getRoleId).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(userRoleList)) {
                roleList.addAll(userRoleList.stream().map(DmpAuthRole::getName).collect(Collectors.toSet()));
            }
        }
        return systemUser;
    }

    @Override
    public DmpResult<SystemUser> findByMobile(String mobile) {
        DmpAuthUser dmpAuthUser = redisCache.getEx(UserCacheKeyEnum.USER.getKey(mobile),
                Duration.ofSeconds(Constants.CLIENT_DETAILS),
                () -> this.baseMapper.findByMobile(mobile));
        return DmpResult.data(dmpAuthUser);
    }

    /**
     * 查询openId
     *
     * @param openId
     * @return
     */
    @Override
    public DmpResult<SystemUser> findByOpenId(String openId) {
        return DmpResult.data(this.baseMapper.selectOne(new LambdaQueryWrapper<DmpAuthUser>().eq(DmpAuthUser::getOpenId, openId)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DmpResult<SystemUser> registUser(RegisterUserDto registerUserDto) {
        SystemUser systemUser = new SystemUser();
        BeanUtils.copyPropertiesIgnoreNullValue(registerUserDto, systemUser);
        systemUser.setSignupApplication(WebUtil.getHeader(CommonConstants.SIGNUPAPPLICATION));
        systemUser.setUserName(registerUserDto.getUsername());
        systemUser.setIsGlobalAdmin(false);
        systemUser.setIsAdmin(false);
        systemUser.setUserCode(IdWorker.getIdStr());
        systemUser.setAvatar(SystemUser.DEFAULT_AVATAR);
        systemUser.setRemark("注册用户");
        systemUser.setState(YesOrNoEnum.Yes.getValue().intValue());
        this.baseMapper.insert(systemUser);
        return DmpResult.data(this.getById(systemUser.getId()));
    }
}


